/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.engine.core.filter;

import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bff.api.dataprocessor.IFilterFieldConvertor;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.spi.jsonser.base.StringUtils;
import com.inspur.edp.commonmodel.engine.api.common.CMEngineUtil;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.GspViewModelElement;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.metadata.rtcustomization.api.CustomizationRtService;
import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.dbInfo.ColumnMapType;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import lombok.var;

import java.util.HashMap;
import java.util.Objects;

public class BffEngineFilterConvertor implements IFilterFieldConvertor {

    private GspViewModel vo;
    private GspBusinessEntity be;
    private HashMap<String, String> filterDic;
    private CustomizationRtService mdService = SpringBeanUtils.getBean(CustomizationRtService.class);

    public BffEngineFilterConvertor(GspViewModel vo, GspBusinessEntity be) {
        this.vo = vo;
        this.be = be;
        initFilterDic();
    }


    private void initFilterDic() {
        filterDic = new HashMap<>();
        if (vo.getIsVirtual() || vo.getMainObject().getIsVirtual())
            return;
        for (var voElement : vo.getMainObject().getAllElementList(false)) {
            if (voElement.getIsVirtual()) {
                continue;
            }
            if (voElement.getIsUdt()) {
                initUdtElement(voElement, voElement.getLabelID(), "");
                continue;
            }

            if (voElement.getHasAssociation()) {
                initAssociationElement(voElement, voElement.getLabelID(), "");
            }
        }
    }

    private void initUdtElement(IGspCommonField voElement, String parentLabel, String returnValue) {
        UnifiedDataTypeDef udt = CMEngineUtil.getMetadataContent(voElement.getUdtID());
        if(udt==null){
            throw new RuntimeException(String.format("未找到ID为：%1$s，名称为：%2$s的udt元数据，请确认该元数据是否已经部署入库。",voElement.getUdtID(),voElement.getUdtName()));
        }
        if (udt != null && udt instanceof SimpleDataTypeDef) {
            initUdtElement(voElement,
                (SimpleDataTypeDef) ((udt instanceof SimpleDataTypeDef) ? udt : null), parentLabel,
                returnValue);

        } else {
            initUdtElement(voElement,
                (ComplexDataTypeDef) ((udt instanceof ComplexDataTypeDef) ? udt : null));
        }
    }

    private void initUdtElement(IGspCommonField voElement, ComplexDataTypeDef udt) {
        if (udt.getDbInfo().getMappingType() == ColumnMapType.SingleColumn) {
            return;
        }
        IGspCommonField beElement = getBeElement(
            (GspViewModelElement) ((voElement instanceof GspViewModelElement) ? voElement : null));
        if (beElement == null) {
            throw new RuntimeException("没有找到字段" + voElement.getLabelID() + "的映射字段");
        }

        for (var mapping : beElement.getMappingRelation()) {
            var beChildEleId = mapping.getKeyInfo();
            var udtEleId = mapping.getValueInfo();
            IGspCommonField beChildElement = getBeChildElement(beElement, beChildEleId);

            var udtElement = udt.findElement(udtEleId);
            if (beChildElement == null || udtElement == null) {
                throw new RuntimeException(
                    "Vo" + vo.getMainObject().getBelongModel().getCode() + "编译失败，多值UDT"
                        + udt.getCode() + "数据库映射有异常");
            }
            buildUdtElementSection(voElement, udtElement, beChildElement, udt);
        }
    }

    private void buildUdtElementSection(IGspCommonField voElement, IGspCommonField udtElement,
        IGspCommonField beElement, ComplexDataTypeDef udt) {

        var udtLabel = voElement.getLabelID() + "." + udtElement.getLabelID();
        initFilterDic(udtLabel, beElement.getLabelID());
        initFilterDic(beElement.getLabelID(), beElement.getLabelID());
    }


    private IGspCommonField getBeChildElement(IGspCommonField beElement, String childId) {

        for (var beChildElement : beElement.getChildElements()) {
            if (childId.equals(beChildElement.getID())) {
                return beChildElement;
            }
        }
        return null;
    }

    private void initUdtElement(IGspCommonField voElement, SimpleDataTypeDef udt, String parentLabel,
        String returnValue) {

        var udtLabel = parentLabel + "." + udt.getCode();
        String udtLabelTemp=udtLabel+"."+udt.getCode();
        initFilterDic(udtLabelTemp, parentLabel);
        IGspCommonField beElement = getBeElement(
            (GspViewModelElement) ((voElement instanceof GspViewModelElement) ? voElement : null));
        if (beElement == null) {
            throw new RuntimeException("没有找到字段" + voElement.getLabelID() + "的映射字段");
        }

        var value = isNullOrEmpty(returnValue) ? beElement.getLabelID() : returnValue;

        initFilterDic(udtLabel, value);
        initFilterDic(voElement.getLabelID(), value);

        if (voElement.getHasAssociation()) {
            var asso = udt.getChildAssociations().get(0);
            initUdtAssociation(voElement, udtLabel, returnValue, asso);
        }
    }

    private void initUdtAssociation(IGspCommonField voElement, String parentLabel,
        String returnValue, GspAssociation udtAsso) {

        var asso = voElement.getChildAssociations().get(0);
        for (var refElement : asso.getRefElementCollection()) {
            IGspCommonField beElement = getBeElement(
                (GspViewModelElement) ((refElement instanceof GspViewModelElement) ? refElement : null));
            if (beElement == null)
                throw new RuntimeException(((GspViewObject) voElement.getBelongObject()).getBelongModel().getCode() +
                    "中，关联字段" + voElement.getLabelID() + "的关联带出字段" + refElement.getLabelID()
                    + "对应的be带出字段不存在");
            IGspCommonField udtRefElement = getUdtRefElement(refElement, udtAsso);
            var childValue = isNullOrEmpty(returnValue) ? beElement.getLabelID() : returnValue;
            var childLabel = isNullOrEmpty(parentLabel) ? refElement.getLabelID() : parentLabel;
            if (udtRefElement != null) {
                childLabel = childLabel + "." + udtRefElement.getLabelID();
            } else {
                childLabel = childLabel + "." + refElement.getLabelID();
            }
            if (refElement.getIsUdt()) {
                initUdtElement(refElement, childLabel, childValue);
            } else {
                initFilterDic(childLabel, childValue);
            }

        }

    }

    private IGspCommonField getUdtRefElement(IGspCommonField refElement, GspAssociation udtAsso) {

        for (IGspCommonField udtRefElement : udtAsso.getRefElementCollection()) {
            if (udtRefElement.getRefElementId().equals(refElement.getRefElementId())) {
                return udtRefElement;
            }
        }
        return null;
    }


    private void initAssociationElement(IGspCommonField voElement, String parentLabel, String returnValue) {
        var asso = voElement.getChildAssociations().get(0);
        initFilterDic(parentLabel+"."+parentLabel,parentLabel);
        for (var refElement : asso.getRefElementCollection()) {
            IGspCommonField beElement = getBeElement(
                (GspViewModelElement) ((refElement instanceof GspViewModelElement) ? refElement : null));

            if(beElement == null)
                throw new RuntimeException("字段"+refElement.getLabelID()+"对应的be字段没有获取到"+((GspViewModelElement)refElement).getMapping().getTargetElementId());
            var childValue = isNullOrEmpty(returnValue) ? beElement.getLabelID() : returnValue;
            var childLabel = isNullOrEmpty(parentLabel) ? refElement.getLabelID() : parentLabel;

            childLabel = childLabel + "." + refElement.getLabelID();
            if (refElement.getIsUdt()) {
                initUdtElement(refElement, childLabel, childValue);
            } else {
                initFilterDic(childLabel, childValue);
            }

        }
    }

    private void initFilterDic(String label, String returnValue) {
        filterDic.put(label, returnValue);
        if (!label.equals(StringUtils.toCamelCase(label))) {
            filterDic.put(StringUtils.toCamelCase(label), returnValue);
        }
    }

    private boolean isNullOrEmpty(String value) {
        return value == null || value.equals("");
    }

    private IGspCommonField getBeElement(GspViewModelElement voElement) {

        var objId = voElement.getMapping().getTargetObjectId();
        if (objId == null || "".equals(objId))
            throw new RuntimeException("字段" + voElement.getCode() + "上没有记录映射对象Id，请打开vo设计器重新添加字段");
        if (objId.equals(be.getMainObject().getID())) {
            return getBeElemet(voElement, be.getMainObject());
        }
        GspBusinessEntity elementBelongBe = null;
        String metadataId = voElement.getMapping().getTargetMetadataId();
        if (metadataId.equals(be.getID())) {
            elementBelongBe = be;
        } else {
            elementBelongBe = CMEngineUtil.getMetadataContent(metadataId);
            Objects.requireNonNull(elementBelongBe, "metadata:" + voElement.getMapping().getTargetMetadataId());
            Objects.requireNonNull(elementBelongBe, "elementBelongBe");
        }

        var beObj = elementBelongBe.findObjectById(objId);
        if (beObj == null)
            throw new RuntimeException("be元数据" + be.getCode() + "上没有找到对象" + objId + "，对应vo对象为" + voElement.getBelongObject().getCode());
        return getBeElemet(voElement, beObj);
    }

    private IGspCommonField getBeElemet(GspViewModelElement voElement, IGspCommonObject beObj) {
        if (!voElement.getIsRefElement()) {
            return beObj.findElement(voElement.getMapping().getTargetElementId());
        }
        for (IGspCommonElement beEle : beObj.getAllElementList(true)) {
            if (beEle.getID().equals(voElement.getMapping().getTargetElementId())) {
                return beEle;
            }
        }

        return null;
    }

    @Override
    public String transFilterField(String fieldName) {
        if (filterDic.containsKey(fieldName))
            return filterDic.get(fieldName);
        return fieldName;
    }
}
